{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Probability calibration of classifiers\n\n\nWhen performing classification you often want to predict not only\nthe class label, but also the associated probability. This probability\ngives you some kind of confidence on the prediction. However, not all\nclassifiers provide well-calibrated probabilities, some being over-confident\nwhile others being under-confident. Thus, a separate calibration of predicted\nprobabilities is often desirable as a postprocessing. This example illustrates\ntwo different methods for this calibration and evaluates the quality of the\nreturned probabilities using Brier's score\n(see https://en.wikipedia.org/wiki/Brier_score).\n\nCompared are the estimated probability using a Gaussian naive Bayes classifier\nwithout calibration, with a sigmoid calibration, and with a non-parametric\nisotonic calibration. One can observe that only the non-parametric model is\nable to provide a probability calibration that returns probabilities close\nto the expected 0.5 for most of the samples belonging to the middle\ncluster with heterogeneous labels. This results in a significantly improved\nBrier score.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "print(__doc__)\n\n# Author: Mathieu Blondel <mathieu@mblondel.org>\n#         Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>\n#         Balazs Kegl <balazs.kegl@gmail.com>\n#         Jan Hendrik Metzen <jhm@informatik.uni-bremen.de>\n# License: BSD Style.\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\n\nfrom sklearn.datasets import make_blobs\nfrom sklearn.naive_bayes import GaussianNB\nfrom sklearn.metrics import brier_score_loss\nfrom sklearn.calibration import CalibratedClassifierCV\nfrom sklearn.model_selection import train_test_split\n\n\nn_samples = 50000\nn_bins = 3  # use 3 bins for calibration_curve as we have 3 clusters here\n\n# Generate 3 blobs with 2 classes where the second blob contains\n# half positive samples and half negative samples. Probability in this\n# blob is therefore 0.5.\ncenters = [(-5, -5), (0, 0), (5, 5)]\nX, y = make_blobs(n_samples=n_samples, centers=centers, shuffle=False,\n                  random_state=42)\n\ny[:n_samples // 2] = 0\ny[n_samples // 2:] = 1\nsample_weight = np.random.RandomState(42).rand(y.shape[0])\n\n# split train, test for calibration\nX_train, X_test, y_train, y_test, sw_train, sw_test = \\\n    train_test_split(X, y, sample_weight, test_size=0.9, random_state=42)\n\n# Gaussian Naive-Bayes with no calibration\nclf = GaussianNB()\nclf.fit(X_train, y_train)  # GaussianNB itself does not support sample-weights\nprob_pos_clf = clf.predict_proba(X_test)[:, 1]\n\n# Gaussian Naive-Bayes with isotonic calibration\nclf_isotonic = CalibratedClassifierCV(clf, cv=2, method='isotonic')\nclf_isotonic.fit(X_train, y_train, sw_train)\nprob_pos_isotonic = clf_isotonic.predict_proba(X_test)[:, 1]\n\n# Gaussian Naive-Bayes with sigmoid calibration\nclf_sigmoid = CalibratedClassifierCV(clf, cv=2, method='sigmoid')\nclf_sigmoid.fit(X_train, y_train, sw_train)\nprob_pos_sigmoid = clf_sigmoid.predict_proba(X_test)[:, 1]\n\nprint(\"Brier scores: (the smaller the better)\")\n\nclf_score = brier_score_loss(y_test, prob_pos_clf, sw_test)\nprint(\"No calibration: %1.3f\" % clf_score)\n\nclf_isotonic_score = brier_score_loss(y_test, prob_pos_isotonic, sw_test)\nprint(\"With isotonic calibration: %1.3f\" % clf_isotonic_score)\n\nclf_sigmoid_score = brier_score_loss(y_test, prob_pos_sigmoid, sw_test)\nprint(\"With sigmoid calibration: %1.3f\" % clf_sigmoid_score)\n\n# #############################################################################\n# Plot the data and the predicted probabilities\nplt.figure()\ny_unique = np.unique(y)\ncolors = cm.rainbow(np.linspace(0.0, 1.0, y_unique.size))\nfor this_y, color in zip(y_unique, colors):\n    this_X = X_train[y_train == this_y]\n    this_sw = sw_train[y_train == this_y]\n    plt.scatter(this_X[:, 0], this_X[:, 1], s=this_sw * 50,\n                c=color[np.newaxis, :],\n                alpha=0.5, edgecolor='k',\n                label=\"Class %s\" % this_y)\nplt.legend(loc=\"best\")\nplt.title(\"Data\")\n\nplt.figure()\norder = np.lexsort((prob_pos_clf, ))\nplt.plot(prob_pos_clf[order], 'r', label='No calibration (%1.3f)' % clf_score)\nplt.plot(prob_pos_isotonic[order], 'g', linewidth=3,\n         label='Isotonic calibration (%1.3f)' % clf_isotonic_score)\nplt.plot(prob_pos_sigmoid[order], 'b', linewidth=3,\n         label='Sigmoid calibration (%1.3f)' % clf_sigmoid_score)\nplt.plot(np.linspace(0, y_test.size, 51)[1::2],\n         y_test[order].reshape(25, -1).mean(1),\n         'k', linewidth=3, label=r'Empirical')\nplt.ylim([-0.05, 1.05])\nplt.xlabel(\"Instances sorted according to predicted probability \"\n           \"(uncalibrated GNB)\")\nplt.ylabel(\"P(y=1)\")\nplt.legend(loc=\"upper left\")\nplt.title(\"Gaussian naive Bayes probabilities\")\n\nplt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}